﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Graphics;

namespace Silverlight3dApp.Learning.Lesson05
{
    public class SpriteManager : DrawableGameComponent
    {
        private SpriteBatch _spriateBatch;
        private UserControlledSprite _player;
        private readonly List<AutomatedSprite> _sprites = new List<AutomatedSprite>();

        private readonly Random _random = new Random();

        private  int _enemySpawnMinMilliseconds = 1000;
        private  int _enemySpawnMaxMilliseconds = 2000;
        private const int nextSpawnTimeChange = 5000;
        private int _timeSinceLastSpawnTimeChange = 0;

        private const int enemyMinSpeed = 2;
        private const int enemyMaxSpeed = 8;

        private const int probabilityDirect = 75;
        private const int probabilityChasing = 20;

        private int _directSpritePointValue = 10;
        private int _chasingSpritePointValue = 20;
        private int _evadingSpritePointValue = 0;

        private int _nextSpawnTime;

        private int _powerUpExpiration;

        public SpriteManager(Game game) : base(game)
        {
        }

        public Vector2 PlayerPosition
        {
            get
            {
                return _player.Position;
            }
        }

        public override void Initialize()
        {
            ResetSpawnTime();
            base.Initialize();
        }

        private void ResetSpawnTime()
        {
            _nextSpawnTime = _random.Next(_enemySpawnMinMilliseconds, _enemySpawnMaxMilliseconds);
        }

        protected void AdjuectSpawnTimes(GameTime gameTime)
        {
            if(_enemySpawnMaxMilliseconds > 500)
            {
                _timeSinceLastSpawnTimeChange += gameTime.ElapsedGameTime.Milliseconds;
                if (_timeSinceLastSpawnTimeChange > nextSpawnTimeChange)
                {
                    _timeSinceLastSpawnTimeChange -= _nextSpawnTime;
                    if(_enemySpawnMaxMilliseconds > 1000)
                    {
                        _enemySpawnMaxMilliseconds -= 100;
                        _enemySpawnMinMilliseconds -= 100;
                    }
                    else
                    {
                        _enemySpawnMaxMilliseconds -= 10;
                        _enemySpawnMinMilliseconds -= 10;
                    }
                }
            }
        }

        protected override void LoadContent()
        {
            _spriateBatch = new SpriteBatch(Game.GraphicsDevice);
            _player = new UserControlledSprite(Game.Content.Load<Texture2D>(@"Images/threerings"), new Vector2((float)(Game.ActualWidth / 2.0f), (float) (Game.ActualHeight / 2.0f)), new Vector2(75, 75), 10, new Vector2(0, 0), new Vector2(6, 8), new Vector2(5, 5));
            _player.Die += PlayerOnDie;
            base.LoadContent();
        }

        private void PlayerOnDie(object sender, EventArgs e)
        {
            ((CollisionGame)Game).CurrentGameState = GameState.GameOver;
        }

        public override void Update(GameTime gameTime)
        {
            _nextSpawnTime -= gameTime.ElapsedGameTime.Milliseconds;
            if (_nextSpawnTime < 0)
            {
                SpawnEnemy();
                ResetSpawnTime();
            }

            if (_powerUpExpiration > 0)
            {
                _powerUpExpiration -= gameTime.ElapsedGameTime.Milliseconds;
                if (_powerUpExpiration <= 0)
                {
                    _powerUpExpiration = 0;
                    _player.ResetScale();
                    _player.ResetSpeed();
                }
            }

            UpdateSprites(gameTime);
            AdjuectSpawnTimes(gameTime);

            base.Update(gameTime);
        }

        protected void UpdateSprites(GameTime gameTime)
        {
            var bounds = Game.GraphicsDevice.Viewport.Bounds;
            _player.Update(gameTime, bounds);
            foreach (var sprite in _sprites.ToArray())
            {
                sprite.Update(gameTime, bounds);
                if (sprite.CollisionRectangle.Intersects(_player.CollisionRectangle))
                {
                    sprite.PlayCollisionSound();
                    if(sprite is DirectSprite)
                    {
                        _player.LivesRemaining--;
                    }
                    else if(sprite is ChasingSprite)
                    {
                        var chasingSpriete = (ChasingSprite)sprite;
                        if(chasingSpriete.Name == "skull")
                        {
                            _powerUpExpiration = 5000;
                            _player.ModifyScale(2.0f);
                        }
                        else if(chasingSpriete.Name == "plus")
                        {
                            _powerUpExpiration = 10000;
                            _player.ModifySpeed(2.0f);
                        }
                    }
                    else if (sprite is EvadingSprite)
                    {
                        _player.LivesRemaining++;
                    }
                    _sprites.Remove(sprite);
                }
                if (sprite.IsOutOfBounds(bounds))
                {
                    ((CollisionGame) Game).AddScore(sprite.ScoreValue);
                    _sprites.Remove(sprite);
                }
            }
        }

        private void SpawnEnemy()
        {
            var frameSize = new Vector2(75, 75);
            var position = new Vector2(_random.Next(0, (int) (Game.GraphicsDevice.Viewport.Width - frameSize.X)), _random.Next(0, (int) (Game.GraphicsDevice.Viewport.Height - frameSize.Y)));
            var speed = new Vector2(_random.Next(enemyMinSpeed, enemyMaxSpeed), _random.Next(enemyMinSpeed, enemyMaxSpeed));

            var random = _random.Next(100);
            if (random < probabilityDirect)
            {
                if (_random.Next(2) == 0)
                {
                    _sprites.Add(new DirectSprite(Game.Content.Load<Texture2D>(@"Images/fourblades"), position, frameSize, 10, new Vector2(0, 0), new Vector2(6, 8), speed, Game.Content.Load<SoundEffect>(@"Audios/fourbladescollision"), _directSpritePointValue));
                }
                else
                {
                    _sprites.Add(new DirectSprite(Game.Content.Load<Texture2D>(@"Images/threeblades"), position, frameSize, 10, new Vector2(0, 0), new Vector2(6, 8), speed, Game.Content.Load<SoundEffect>(@"Audios/threebladescollision"), _directSpritePointValue));
                }
            }
            else if (random < probabilityDirect + probabilityChasing)
            {
                if (_random.Next(2) == 0)
                {
                    _sprites.Add(new ChasingSprite(Game.Content.Load<Texture2D>(@"Images/skullball"), position, frameSize, 10, new Vector2(0, 0), new Vector2(6, 8), speed, Game.Content.Load<SoundEffect>(@"Audios/skullcollision"), _chasingSpritePointValue, this, 350, "skull"));
                }
                else
                {
                    _sprites.Add(new ChasingSprite(Game.Content.Load<Texture2D>(@"Images/plus"), position, frameSize, 10, new Vector2(0, 0), new Vector2(6, 4), speed, Game.Content.Load<SoundEffect>(@"Audios/pluscollision"), _chasingSpritePointValue, this, 300, "plus"));
                }
            }
            else
            {
                _sprites.Add(new EvadingSprite(Game.Content.Load<Texture2D>(@"Images/bolt"), position, frameSize, 10, new Vector2(0, 0), new Vector2(6, 8), speed, Game.Content.Load<SoundEffect>(@"Audios/boltcollision"), _evadingSpritePointValue, this, 100));
            }
        }

        public override void Draw(GameTime gameTime)
        {
            _spriateBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend);
            _player.Draw(gameTime, _spriateBatch);
            foreach (var sprite in _sprites)
            {
                sprite.Draw(gameTime, _spriateBatch);
            }
            _spriateBatch.End();
            base.Draw(gameTime);
        }
    }
}